﻿#include "imageviewer.h"

#include <QFile>
#include <QWheelEvent>

ImageViewer::ImageViewer(QWidget *parent) : QGraphicsView(parent)
{
    error_no = 0x00;

    pixmap_item = nullptr;

    // 设置场景
    scene = new QGraphicsScene;
    this->setScene(scene);

    // 消除边缘间距
    this->setViewportMargins(-2, -2, -2, -2);

    // 设置背景颜色
    this->setBackgroundBrush(QColor(25, 25, 25));

    // 设置最小尺寸
    this->setMinimumSize(500, 420);

    // 移除边框 好像没什么用
//    this->setFrameShape(QGraphicsView::Shape::Box);

    // 启用拖拽模式
    this->setDragMode(QGraphicsView::DragMode::ScrollHandDrag);

    // 清除视图锚点
    this->setResizeAnchor(QGraphicsView::ViewportAnchor::NoAnchor);

    // 平滑渲染图
    this->setRenderHint(QPainter::RenderHint::SmoothPixmapTransform);

    // 缓存背景
    this->setCacheMode(QGraphicsView::CacheModeFlag::CacheBackground);

    // 隐藏滚动条
    this->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
    this->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);

    // 取消自动保存
    this->setOptimizationFlag(QGraphicsView::OptimizationFlag::DontSavePainterState);

    // 智能渲染视图的显示
    this->setViewportUpdateMode(QGraphicsView::ViewportUpdateMode::SmartViewportUpdate);

    bindSignSlot();
}

ImageViewer::~ImageViewer()
{
    if(this->pixmap_item) {
        scene->removeItem(this->pixmap_item);
        scene->clear();
        delete this->pixmap_item;
        this->pixmap_item = nullptr;
    }
}

QString ImageViewer::getLastErrorInfo()
{
    QString str;
    switch (error_no) {
    case 0x00:
        str = "";
        break;
    case 0x0001:
        str = "图片不存在";
        break;
    }
    return str;
}

bool ImageViewer::loadImage(const QString &filepath)
{
    QPixmap pixmap(filepath);
    if(pixmap.isNull()) {
        error_no = 0x01;
        return false;
    }
    if(this->pixmap_item) {
        zoom_total = 1.0;
        this->resetTransform();
        scene->removeItem(this->pixmap_item);
        scene->clear();
        delete this->pixmap_item;
        this->pixmap_item = nullptr;
    }
    this->pixmap_item = new QGraphicsPixmapItem(pixmap);
    this->pixmap_item->setTransformationMode(Qt::TransformationMode::SmoothTransformation);

    scene->addItem(this->pixmap_item);
    if(ratio() < 1) {
        // 原图超过窗口
        this->fitInView(this->pixmap_item, Qt::AspectRatioMode::KeepAspectRatio);
    }

    return true;
}

void ImageViewer::wheelEvent(QWheelEvent *e)
{
    int angle = e->angleDelta().y(); // 正数代表向前
    if(angle < 0 && zoom_total == 1) {
        return;
    }
    zoom_origin = e->pos();
    zoom_scene_origin = mapToScene(zoom_origin);
    zoom((angle > 0) ? 1.1f : 0.9f);
}

void ImageViewer::resizeEvent(QResizeEvent *e)
{
    if(this->pixmap_item) {
        float factor = this->ratio() * zoom_total / m11();
        scale(factor, factor);
    }
}

void ImageViewer::enterEvent(QEvent *e)
{
    setTransformationAnchor(QGraphicsView::ViewportAnchor::NoAnchor);
    QGraphicsView::enterEvent(e);
}

void ImageViewer::leaveEvent(QEvent *e)
{
    setTransformationAnchor(QGraphicsView::ViewportAnchor::AnchorViewCenter);
    QGraphicsView::enterEvent(e);
}

void ImageViewer::slot_animValueChange(const QVariant &value)
{
    float factor = value.toFloat() / zoom_total;
    if(factor == zoom_total) {
        return ;
    }
    zoom_total = value.toFloat();
    this->scale(factor, factor);
    QPointF delta = mapToScene(zoom_origin) - zoom_scene_origin;
    translate(delta.x(), delta.y());
}

void ImageViewer::bindSignSlot()
{
    connect(&zoom_anim, &QVariantAnimation::valueChanged,
            this, &ImageViewer::slot_animValueChange);
}

float ImageViewer::ratio()
{
    QRectF scene_rect = this->sceneRect();
    float pw = this->width() / scene_rect.width();
    float ph = this->height() / scene_rect.height();
    return qMin(ph, pw);
}

void ImageViewer::zoom(float factor)
{
    bool running = zoom_anim.state() == QVariantAnimation::State::Running;
    if(running) {
        factor *= factor; // 加速缩放
    }
    zoom_anim.setStartValue(zoom_total);
    zoom_anim.setEndValue(qMax(1.0f, zoom_total*factor));
    zoom_anim.start();
}

float ImageViewer::m11()
{
    return transform().m11();
}


















